/*
 *  (c) E.S.A.
 */

#include "tokenizer.h"
#include "msg_logger.h"
#include "socket_utilities.h"
#include "global_data.h"
#include "server_mode.h"
#include "remote_party.h"
#include "process_data.h"

#include <iostream>
#include <fstream>
#include <cassert>
#include <pthread.h>
#include <stdlib.h>
using namespace std;

void init_buffer_struct (buff_t *buffer)
{
	sem_init (&buffer->full_sem, 0, 0);
	sem_init (&buffer->empty_sem,0, CIRCULAR_BUF_SIZE);
	sem_init (&buffer->put_mutex, 0, 1);
	sem_init (&buffer->get_mutex, 0, 1);
	buffer->nextin = buffer->nextout = 0;
}

void destroy_buffer_struct (buff_t *buffer)
{
	sem_destroy (&buffer->full_sem);
	sem_destroy (&buffer->empty_sem);
	sem_destroy (&buffer->put_mutex);
	sem_destroy (&buffer->get_mutex);
	buffer->nextin = buffer->nextout = 0;
}


void init_global_data ()
{
	global.quit_flag = false;

	init_buffer_struct (&global.recv_buff);
	init_buffer_struct (&global.cli_send_buff);

}

int read_from_file (char* file_name)
{
	string line;
	String_Tokenizer line_tok;
	ifstream config_file(file_name);
	line_type type = UNKNOWN;
	std::string ip, port_st;

	if (config_file.is_open())
	{
		while (! config_file.eof() ) 
		{
			getline (config_file,line);

			// if starts with "#" => comment
			if (line.find_first_of("#") == 0){
				if (line.find("local") != string::npos){
					type = LOCAL;
				}
				if (line.find("remote") != string::npos){
					type = REMOTE;
				}
				continue;
			}

			line_tok.set_string(line, " \t");
			if ((type == LOCAL) or (type == REMOTE)){
				assert (line_tok.has_more_tokens());
				ip = line_tok.next_token();
				port_st = line_tok.next_token();
			}
			switch (type){
			case LOCAL:
			{
				global.local_addr.ip = ip;
				global.local_addr.port = atoi (port_st.c_str());
				break;
			}
			case REMOTE:
			{
				remote_srv* remote_server = new remote_srv(ip, atoi (port_st.c_str()));
				global.list_of_servers.add_element(remote_server);
				break;
			}	
			default:
				break;
			}
		}
	}
	else{
		MSG_LOG (WARN, "Unable to open file");
		return -1;
	}

	config_file.close();
	return 0;

}


int main(int argc, char* argv[])
{
	if(argc != 2) {
		MSG_LOG (WARN, "SYNTAX: " << argv[0] << " config_file \n");
		return 0;
	}

	global.file_name = argv[1];
	if (read_from_file (global.file_name) == -1){
		return 0;
	}

	init_global_data ();

	// create thread:
	pthread_t server_conn_thread;
	if(pthread_create(&server_conn_thread, NULL, server_conn_main, NULL) != 0){
		MSG_LOG (ERR, "could not create server conn thread");
		return 1;
	}
	pthread_t process_data_thread;
	if(pthread_create(&process_data_thread, NULL, process_data_main, NULL) != 0){
		MSG_LOG (ERR, "could not create process data thread");
		return 1;
	}

	// wait for join:
	if(pthread_join(server_conn_thread, NULL) != 0){
		MSG_LOG (ERR, "could not join server conn thread");
		return 1;
	}
	if(pthread_join(process_data_thread, NULL) != 0){
		MSG_LOG (ERR, "could not join server conn thread");
		return 1;
	}

	destroy_buffer_struct (&global.recv_buff);
	destroy_buffer_struct (&global.cli_send_buff);

	return 0;
}

